/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.xadrez.ia;

import com.xadrez.Principal;
import com.xadrez.exception.NumeroDeJogadorExcessoException;
import com.xadrez.modelo.Bispo;
import com.xadrez.modelo.Cavalo;
import com.xadrez.modelo.Peao;
import com.xadrez.modelo.Peca;
import com.xadrez.modelo.Posicao;
import com.xadrez.modelo.Rainha;
import com.xadrez.modelo.Rei;
import com.xadrez.modelo.Tabuleiro;
import com.xadrez.modelo.Torre;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author fabricio
 */
public class MiniMax extends IA {

    TabuleiroIA tabuleiro = null;
    private int profundidade;
    private static final int INFINITO = 10000;

    private void inicialize(Tabuleiro tabuleiro) throws NumeroDeJogadorExcessoException {
            this.tabuleiro = new TabuleiroIA(tabuleiro);
    }

    public MiniMax(String nome, int dificuldade) throws NumeroDeJogadorExcessoException{
        super(nome);
        setProfundidade(dificuldade);
    }
        
// 

    private TabuleiroIA executeMiniMax(TabuleiroIA tabuleiro, int profundidade) throws NumeroDeJogadorExcessoException {
        TabuleiroIA tabuleiroIdeal = new TabuleiroIA(tabuleiro);
        if ((profundidade == 0) || (!tabuleiro.hasJogadas())) {
            return tabuleiro;
        } else if (!tabuleiro.getJogadorDaVez().equals(this)) {
            tabuleiroIdeal.setPeso(INFINITO);
            for (Peca peca : tabuleiro.getPecasJogador(getIdOponente())) {
                for (Posicao posicao : peca.recuperaMovimentosPossiveis()) {
                    TabuleiroIA tabuleiroTemp = (TabuleiroIA) tabuleiro.clone();
                    tabuleiroTemp.Mover(peca, posicao);
                    tabuleiroTemp.setPeso(fstatus(tabuleiroTemp));
//                    TabuleiroIA.cont++;
                    tabuleiroIdeal = min(tabuleiroIdeal, executeMiniMax(tabuleiroTemp, profundidade - 1));
                }
            }
        } else {
            tabuleiroIdeal.setPeso(-INFINITO);
            for (Peca peca : tabuleiro.getPecasJogador(getId())) {
                for (Posicao posicao : peca.recuperaMovimentosPossiveis()) {
                    TabuleiroIA tabuleiroTemp = (TabuleiroIA) tabuleiro.clone();
                    tabuleiroTemp.Mover(peca, posicao);
                    tabuleiroTemp.setPeso(fstatus(tabuleiroTemp));
                    Jogada jogada = new Jogada(peca, posicao);
//                    TabuleiroIA.cont++;
                    tabuleiroTemp.setJogada(jogada);
                    tabuleiroIdeal = max(tabuleiroIdeal, executeMiniMax(tabuleiroTemp, profundidade - 1));
                }

            }

        }
        return tabuleiroIdeal;
    }

    // conveção se positivo jogador ganhado, 0 empate, negativo perdendo
    private int fstatus(TabuleiroIA tabuleiro) {
        int pontos = 0;
        for (Peca peca : tabuleiro.getPecasJogador(getId())) {
            if (peca instanceof Bispo) {
                pontos = pontos + 7;
            } else if (peca instanceof Cavalo) {
                pontos = pontos + 5;
            } else if (peca instanceof Peao) {
                pontos = pontos + 2;
            } else if (peca instanceof Rainha) {
                pontos = pontos + 17;
            } else if (peca instanceof Rei) {
                pontos = pontos + 25;
            } else if (peca instanceof Torre) {
                pontos = pontos + 7;
            }

        }

        for (Peca peca : tabuleiro.getPecasJogador(getIdOponente())) {
            if (peca instanceof Bispo) {
                pontos = pontos - 7;
            } else if (peca instanceof Cavalo) {
                pontos = pontos - 4;
            } else if (peca instanceof Peao) {
                pontos = pontos - 1;
            } else if (peca instanceof Rainha) {
                pontos = pontos - 17;
            } else if (peca instanceof Rei) {
                pontos = pontos - 25;
            } else if (peca instanceof Torre) {
                pontos = pontos - 7;
            }
        }
        return pontos;
    }

    private TabuleiroIA min(TabuleiroIA tabA, TabuleiroIA tabB) {
        int aux = tabA.compareTo(tabB); 
        
        if ( aux == 0) {
            aux = random();
        }
        if(aux == -1){
            return tabA;
        } else {
            return tabB;
        }
    }

    private TabuleiroIA max(TabuleiroIA tabA, TabuleiroIA tabB) {
        int aux = tabA.compareTo(tabB);
        
        if ( aux == 0) {
            aux = random();
        }
                
        if (aux == 1) {
            return tabA;
        } else {
            return tabB;
        }
    }
    
    private int random(){
        double aux = Math.random();
        if (aux <0.5)
            return -1;
        else
            return 1;
   }

    @Override
    public Jogada jogar(){
        TabuleiroIA tab = null;
        try {
            inicialize(Principal.getTabuleiro());
            tab = executeMiniMax(this.tabuleiro, this.getProfundidade());
        } catch (NumeroDeJogadorExcessoException ex) {
            Logger.getLogger(MiniMax.class.getName()).log(Level.SEVERE, null, ex);
        }
        Jogada jogada = tab.getJogada();
        jogada.setPeca(Principal.getTabuleiro(jogada.getPeca().getPosicaoNoTabuleiro()));
        
        try {
            jogada.setPosicaoAntiga(jogada.getPeca().getPosicaoNoTabuleiro());
        } catch (CloneNotSupportedException ex) {
            Logger.getLogger(MiniMax.class.getName()).log(Level.SEVERE, null, ex);
        }
        jogada.executar();
        return jogada;
    }

    private int getIdOponente() {
        return getId() % 2 + 1;
    }

    public int getProfundidade() {
        return profundidade;
    }

    public void setProfundidade(int profundidade) {
        this.profundidade = profundidade;
    }
}
